package net.ccfish.jvue.service.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import net.ccfish.common.mybatis.BaseMapper;
import net.ccfish.jvue.autogen.dao.JvueModuleMapper;
import net.ccfish.jvue.autogen.dao.JvueRoleApiMapper;
import net.ccfish.jvue.autogen.dao.JvueRoleMapper;
import net.ccfish.jvue.autogen.dao.JvueRolePageMapper;
import net.ccfish.jvue.autogen.dao.JvueRoleSegmentMapper;
import net.ccfish.jvue.autogen.model.JvueModule;
import net.ccfish.jvue.autogen.model.JvueRole;
import net.ccfish.jvue.autogen.model.JvueRoleApi;
import net.ccfish.jvue.autogen.model.JvueRolePage;
import net.ccfish.jvue.autogen.model.JvueRoleSegment;
import net.ccfish.jvue.domain.dao.JvueExRoleApiMapper;
import net.ccfish.jvue.domain.dao.JvueExRolePageMapper;
import net.ccfish.jvue.domain.dao.JvueExRoleSegmentMapper;
import net.ccfish.jvue.domain.model.JvueExPage;
import net.ccfish.jvue.domain.model.JvueExRoleApi;
import net.ccfish.jvue.domain.model.JvueExRoleSegment;
import net.ccfish.jvue.service.JvueRoleService;
import net.ccfish.jvue.service.model.ModuleAndPages;
import net.ccfish.jvue.service.model.PageRoleGrant;
import net.ccfish.jvue.service.model.RolePageDetails;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.weekend.WeekendSqls;

/**
 * Generated by Spring Data Generator on 31/01/2018
 */
@Service
public class JvueRoleServiceImpl implements JvueRoleService, Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1581111046496183715L;

    private JvueRoleMapper jvueRoleMapper;

    @Autowired
    private JvueModuleMapper jvueModuleMapper;
    
    @Autowired
    private JvueExRoleApiMapper jvueRoleApiMapper;
    
    @Autowired
    private JvueExRolePageMapper exRolePageMapper;

    @Autowired
    private JvueRolePageMapper rolePageMapper;
    
    @Autowired
    private JvueRoleApiMapper roleApiMapper;
    
    @Autowired
    private JvueRoleSegmentMapper roleSegmentMapper;
    
    @Autowired
    private JvueExRoleSegmentMapper jvueRoleSegmentMapper;

    @Autowired
    public JvueRoleServiceImpl(JvueRoleMapper jvueRoleMapper) {
        this.jvueRoleMapper = jvueRoleMapper;
    }

    @Override
    public BaseMapper<JvueRole> baseMapper() {
        return this.jvueRoleMapper;
    }

    @Override
    @Cacheable(value = "rolePage", key = "#roles")
    public ModuleAndPages<Integer> findModuleAndPage(List<Integer> roles) {

        Assert.notEmpty(roles, "未授权");
        
        // 根据权限查询对应的菜单和modules/segments
        ModuleAndPages<Integer> moduleAndPages = new ModuleAndPages<>();

//        Example examplePage = new Example.Builder(JvueRolePage.class)
//                .where(WeekendSqls.<JvueRolePage>custom().andIn(JvueRolePage::getRoleId, roles))
//                .build();
        
        List<JvueExPage> rolePages = exRolePageMapper.selectPageByRole(roles);

        List<Integer> moduleIds = rolePages.stream().map(page -> page.getModuleId()).distinct()
                .collect(Collectors.toList());

        Example exampleModule = new Example.Builder(JvueModule.class)
                .where(WeekendSqls.<JvueModule>custom().andIn(JvueModule::getId, moduleIds))
                .build();
        List<JvueModule> modules = jvueModuleMapper.selectByExample(exampleModule);

        // 查询角色对应的segments
        MultiValueMap<Integer, Integer> segmentMap = new LinkedMultiValueMap<>();

        List<JvueExRoleSegment> roleSegments = jvueRoleSegmentMapper.selectSegmentByRole(roles);
        
        for (JvueExRoleSegment rs: roleSegments) {
            segmentMap.add(rs.getSegment().getPageId(), rs.getSegment().getSegmentCode());
        }
        
        // 生成返回结果
        moduleAndPages.setPages(rolePages);
        moduleAndPages.setModules(modules);
        moduleAndPages.setSegments(segmentMap);

        return moduleAndPages;
    }

    @Override
    public JvueRole updateEnabled(Integer id, Integer enabled) {
        
        JvueRole jvueRole = jvueRoleMapper.selectByPrimaryKey(id);
                
        if (jvueRole != null) {
            jvueRole.setEnabled(enabled);
            jvueRoleMapper.updateByPrimaryKeySelective(jvueRole);
            return jvueRole;
        }

        return null;
    }

    @Override
    @Cacheable(value = "roleApi", key = "#apiId")
    public List<Integer> getRolesByApi(Integer apiId) {
        List<JvueExRoleApi> jvueRoleApis = jvueRoleApiMapper.selectByApi(apiId);
        return jvueRoleApis.stream().map(roleApi -> roleApi.getRole().getId()).collect(Collectors.toList());
    }

    @Override
    public RolePageDetails<Integer> getRoleInfo(Integer id) {

        List<Integer> roles = Arrays.asList(id);
        
        // 根据权限查询对应的菜单和modules/segments
        RolePageDetails<Integer> moduleAndPages = new RolePageDetails<>();
        
        List<JvueExPage> rolePages = exRolePageMapper.selectPageByRole(roles);
        
        if (rolePages.isEmpty()) {

            // 首次查询，无权限
            moduleAndPages.setPages(rolePages);
            moduleAndPages.setModules(new ArrayList<>());
            moduleAndPages.setSegments(new LinkedMultiValueMap<>());
            moduleAndPages.setApis(new LinkedMultiValueMap<>());
        } else {
        
            List<Integer> moduleIds = rolePages.stream().map(page -> page.getModuleId()).distinct()
                    .collect(Collectors.toList());
    
            Example exampleModule = new Example.Builder(JvueModule.class)
                    .where(WeekendSqls.<JvueModule>custom().andIn(JvueModule::getId, moduleIds))
                    .build();
            List<JvueModule> modules = jvueModuleMapper.selectByExample(exampleModule);
            
            // 查询角色对应的segments
            MultiValueMap<Integer, Integer> segmentMap = new LinkedMultiValueMap<>();
    //        SearchCriteria<JvueRoleSegment> roleSegmentCriterias = new SearchCriteria<>();
    //        roleSegmentCriterias.add(JpaRestrictions.eq("role.id", id, false));
    //        List<JvueRoleSegment> roleSegments = jvueRoleSegmentMapper.findAll(roleSegmentCriterias);
            List<JvueExRoleSegment> roleSegments = jvueRoleSegmentMapper.selectSegmentByRole(roles);
            
            for (JvueExRoleSegment rs: roleSegments) {
                segmentMap.add(rs.getSegment().getPageId(), rs.getSegment().getSegmentCode());
            }
            
            // 查询角色对应的API
            MultiValueMap<Integer, Integer> apiMap = new LinkedMultiValueMap<>();
            List<JvueExRoleApi> roleApis = jvueRoleApiMapper.selectByRole(roles);
            
            for (JvueExRoleApi rs: roleApis) {
                apiMap.add(rs.getApi().getPageId(), rs.getApi().getApiCode());
            }
            moduleAndPages.setPages(rolePages);
            moduleAndPages.setModules(modules);
            moduleAndPages.setSegments(segmentMap);
            moduleAndPages.setApis(apiMap);
        }

        return moduleAndPages;
    
    }

    @Override
    @CacheEvict(value = {"rolePage", "roleApi"}, allEntries = true)
    public int grant(Integer id, Integer moduleId, List<PageRoleGrant> pageRoles) {

        Assert.notNull(id, "角色ID不能为空");
        
        if (pageRoles != null && !pageRoles.isEmpty()) {
            
            // RolePageDetails<Integer> roleInfo = getRoleInfo(id);
            List<Integer> roledPageIds = exRolePageMapper.selectPageByRoleAndModule(id, moduleId);
            List<Integer> roledApiIds = jvueRoleApiMapper.selectApiByRoleAndModule(id, moduleId);
            List<Integer> roledSegmentIds = jvueRoleSegmentMapper.selectSegmentByRoleAndModule(id, moduleId);
            
            List<Integer> pageIds = new ArrayList<>();
            List<Integer> apiIds = new ArrayList<>();
            List<Integer> segmentIds = new ArrayList<>();
            
            for (PageRoleGrant pageRole : pageRoles) {
                
                // TODO 更新权限
                pageIds.add(pageRole.getPageId());
                
                // 保存画面权限
                for (Integer apiId : pageRole.getApiIds()) {
                    apiIds.add(apiId);
                }

                for (Integer segmentId : pageRole.getSegmentIds()) {
                    segmentIds.add(segmentId);
                }
            }
            
            // 差分数据，保存
            Collection<Integer> addedList = new ArrayList<>();
            Collection<Integer> removedList = new ArrayList<>();
            
            // 画面
            addedList = CollectionUtils.subtract(pageIds, roledPageIds);
            removedList = CollectionUtils.subtract(roledPageIds, pageIds);
            
            for (Integer pageId: addedList) {
                JvueRolePage rolePage = new JvueRolePage();
                rolePage.setPageId(pageId);
                rolePage.setRoleId(id);
                rolePageMapper.insert(rolePage);
            }
            for (Integer pageId: removedList) {
                JvueRolePage rolePage = new JvueRolePage();
                rolePage.setPageId(pageId);
                rolePage.setRoleId(id);
                rolePageMapper.deleteByPrimaryKey(rolePage);
            }

            // API
            addedList = CollectionUtils.subtract(apiIds, roledApiIds);
            removedList = CollectionUtils.subtract(roledApiIds, apiIds);

            for (Integer apiId: addedList) {
                JvueRoleApi roleApi = new JvueRoleApi();
                roleApi.setApiId(apiId);
                roleApi.setRoleId(id);
                roleApiMapper.insert(roleApi);
            }
            for (Integer apiId: removedList) {
                JvueRoleApi roleApi = new JvueRoleApi();
                roleApi.setApiId(apiId);
                roleApi.setRoleId(id);
                roleApiMapper.deleteByPrimaryKey(roleApi);
            }

            // Segment
            addedList = CollectionUtils.subtract(segmentIds, roledSegmentIds);
            removedList = CollectionUtils.subtract(roledSegmentIds, segmentIds);

            for (Integer segmentId: addedList) {
                JvueRoleSegment roleSegment = new JvueRoleSegment();
                roleSegment.setSegmentId(segmentId);
                roleSegment.setRoleId(id);
                roleSegmentMapper.insert(roleSegment);
            }
            for (Integer segmentId: removedList) {
                JvueRoleSegment roleSegment = new JvueRoleSegment();
                roleSegment.setSegmentId(segmentId);
                roleSegment.setRoleId(id);
                roleSegmentMapper.deleteByPrimaryKey(roleSegment);
            }
            
            return 1;
        }
        
        return 0;
    }


    // TODO
    // 开发/调试模式下，开发者等特殊角色可以无视enabled直接启用，方便调试画面
    
}
